package presenter;

import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.Intent;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.widget.Toast;

import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;

import io.reactivex.Observable;
import io.reactivex.ObservableEmitter;
import io.reactivex.ObservableOnSubscribe;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;
import model.IMainModel;

import model.bean.DisplayData;
import model.bean.RawData;
import model.bluetooth.BluetoothService;
import model.bluetooth.Constants;
import model.bluetooth.DeviceListActivity;
import model.impl.MainModelImpl;
import ui.activity.BaseActivity;
import ui.fragment.EnsureResetBTFragment;
import ui.view.IMainView;
import util.Troika;

/**
 * Created by 10153 on 2018/7/16.
 */

public class MainPresenter extends BasePresenter<IMainView> {
    
    private static final String TAG = "MainPresenter";
    
    public static final int REQUEST_CONNECT_DEVICE_SECURE = 1;
    public static final int REQUEST_CONNECT_DEVICE_INSECURE = 2;
    public static final int REQUEST_ENABLE_BT = 3;
    
    
    private IMainModel mainModel = new MainModelImpl();
    private BluetoothService bluetoothService = null;
    private BluetoothAdapter bluetoothAdapter = null;
    private boolean isBTHasStarted = false;
    
    private MyHandler myHandler;
    private List<String> listBuff = new ArrayList<>();
    private String stringBuff = "";
    
    public MainPresenter(IMainView mView) {
        super(mView);
    }
    
    @Override
    protected void onCreate() {
        super.onCreate();
        myHandler = new MyHandler(this);
//        bluetoothService = new BluetoothService(getContext(), myHandler);
    }
    
    @Override
    public void onDestroy() {
        super.onDestroy();
        if(bluetoothService != null){
            bluetoothService.stop();
        }
    }
    
    @Override
    public void onResume() {
        super.onResume();
        if(isBTHasStarted){
            if(bluetoothService.getState() == BluetoothService.STATE_NONE)
                bluetoothService.start();
        }
    }
    
    public void fillData(){
        if(!isViewAttached()){
            Log.d(TAG, "fillData: hasn't attach view");
        }else {
            Observable.create(new ObservableOnSubscribe<String>() {
                
                @Override
                public void subscribe(ObservableEmitter<String> e) throws Exception {
                    e.onNext(mainModel.getDataFromLocal());
                    //e.onNext(mainModel.getDataFromRemote());    //耗时方法
                    e.onComplete();
                }
            }).subscribeOn(Schedulers.io())
                    //可能需要添加解析数据过程
                    .observeOn(Schedulers.computation())
                    .map(new Function<String, String>() {
                        
                        @Override
                        public String apply(String s) throws Exception {
                            return Troika.count(s);                   //
                        }
                    }).observeOn(AndroidSchedulers.mainThread())
                    .subscribe(new Observer<String>() {
                        
                        @Override
                        public void onSubscribe(Disposable d) {
                        
                        }
                        
                        @Override
                        public void onNext(String s) {
                            if(s != null){
                                getView().fillData(s);
                            }else {
                                getView().fillData("empty data!");
                            }
                        }
                        
                        @Override
                        public void onError(Throwable e) {
                        
                        }
                        
                        @Override
                        public void onComplete() {
                        
                        }
                    });
        }
    }
    
    public void startBTService(){
        if(!isBTHasStarted){
            ensureBTAvailable();
            return;
        }
        if(bluetoothService.getState() == BluetoothService.STATE_CONNECTED){
            showResetDialog();
            return;
        }
        bluetoothService.start();
        Toast.makeText(getContext(), "bluetooth service start!", Toast.LENGTH_SHORT).show();
    }
    
    public void ensureDiscoverable() {
        if(!isBTHasStarted){
            ensureBTAvailable();
            return;
        }
        if (bluetoothAdapter.getScanMode() !=
                BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
            Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
            discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
            getContext().startActivity(discoverableIntent);
        }
    }
    
    public void connectDevice(Intent data, boolean secure){
        String address = data.getExtras()
                .getString(DeviceListActivity.EXTRA_DEVICE_ADDRESS);
        // Get the BluetoothDevice object
        BluetoothDevice device = bluetoothAdapter.getRemoteDevice(address);
        // Attempt to connect to the device
        bluetoothService.connect(device, secure);
    }
    
    public void startScanActivity(int mode){
        if(!isBTHasStarted){
            ensureBTAvailable();
            return;
        }
        if(bluetoothService.getState() == BluetoothService.STATE_CONNECTED){
            showResetDialog();
            return;
        }
        Intent intent = new Intent(getContext(), DeviceListActivity.class);
        ((Activity)getContext()).startActivityForResult(intent, mode);
    }
    
    public boolean isBTHasStarted(){
        return isBTHasStarted;
    }
    
    public void setBTState(boolean state){
        this.isBTHasStarted = state;
    }
    
    public void resetBTState(){
        if(bluetoothService != null){
            bluetoothService.stop();
            bluetoothService.start();
            Toast.makeText(getContext(), "BT state has been reseted!", Toast.LENGTH_SHORT).show();
        }
    }
    
    private void showResetDialog(){
        EnsureResetBTFragment dialog = new EnsureResetBTFragment();
        dialog.show(((BaseActivity)getContext()).getSupportFragmentManager(), "resetDialog");
    }
    
    //由handler调用 即 当ConnectedThread取出一单位的数据后会通知handler调用该方法
    private void handleBTMessage(final byte[] bytes, final int length){
        Observable.create(new ObservableOnSubscribe<RawData>() {                                    //创建事件发生器 即被观察者
    
            @Override
            public void subscribe(ObservableEmitter<RawData> e) throws Exception {
                //解析
                e.onNext(mainModel.analyzeData(bytes, length));//将获取的字节数据传入model层方法进行解析,请在analyzeData方法实现该方法（默认为耗时操作） 解析完成后将返回RawData并传入下一个过程
            }
        })
                .subscribeOn(Schedulers.newThread())//将事件发生线程设定在新建线程
                .observeOn(Schedulers.computation())//将下一步的观察线程设定在计算线程
                .map(new Function<RawData, DisplayData>() {                                         //map变换
    
                    @Override
                    public DisplayData apply(RawData data) throws Exception {
                        //保存原始数据
                        mainModel.saveData(data);
                        //计算
                        DisplayData displayData = mainModel.handleRawData(data);//将由上一步传来的RawData数据传入model层进行计算 请在handleRawData方法实现troika心率计算计算&行为分析和 计算完成后返回DisplayData
                        //保存展示数据
                        mainModel.saveData(displayData);
                        return displayData;
                    }
                })
                .observeOn(AndroidSchedulers.mainThread())//将下一步的观察线程设定在主线程
                .subscribe(new Observer<DisplayData>() {                                            //创建观察者并订阅（subscribe）
    
                    @Override
                    public void onSubscribe(Disposable d) {
                        //调用subscribe时调用此方法 这里不需要的
                    }
    
                    @Override
                    public void onNext(DisplayData displayData) {
                        //接收上一步传来的displayData并更新ui
                        getView().refreshData(displayData.getState());//这里为测试用 请根据实际要展示的数据修改接口的参数和实现
                    }
    
                    @Override
                    public void onError(Throwable e) {
                        e.printStackTrace();
                    }
            
                    @Override
                    public void onComplete() {
                        //这里没有被调用
                    }
                });
    }
    
    private void ensureBTAvailable(){
        if(bluetoothAdapter == null){
            bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
            if(bluetoothAdapter == null) {
                Toast.makeText(getContext(), "Bluetooth is not available", Toast.LENGTH_LONG).show();
                return;
            }
        }
        if(bluetoothService == null){
            bluetoothService  = new BluetoothService(getContext(), myHandler);
        }
        if(!bluetoothAdapter.isEnabled()){
            Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            ((BaseActivity)getContext()).startActivityForResult(intent, REQUEST_ENABLE_BT);
        }else{
            isBTHasStarted = true;
        }
    }

    private static class MyHandler extends Handler{
        WeakReference<MainPresenter> weakPRef;

        MyHandler(MainPresenter presenter) {
            weakPRef = new WeakReference<>(presenter);
        }

        @Override
        public void handleMessage(Message msg) {
            final MainPresenter presenter = weakPRef.get();
            if (presenter != null) {
                switch (msg.what) {
                    case Constants.MESSAGE_STATE_CHANGE:
                        switch (msg.arg1) {
                            case BluetoothService.STATE_CONNECTED:
                                Toast.makeText(presenter.getContext(), "connected!", Toast.LENGTH_SHORT).show();
                                break;
                            case BluetoothService.STATE_CONNECTING:
                                break;
                            case BluetoothService.STATE_LISTEN:
                                break;
                            case BluetoothService.STATE_NONE:
                                Toast.makeText(presenter.getContext(), "bt none!", Toast.LENGTH_SHORT).show();
                                break;
                        }
                        break;
                    case Constants.MESSAGE_WRITE:
                        byte[] writeBuf = (byte[]) msg.obj;
                        // construct a string from the buffer
                        String writeMessage = new String(writeBuf);
                        break;
                    case Constants.MESSAGE_READ:
                        byte[] readBuf = (byte[]) msg.obj;
                        // construct a string from the valid bytes in the buffer
                        presenter.handleBTMessage(readBuf, msg.arg1);
                        break;
                    case Constants.MESSAGE_DEVICE_NAME:
                        // save the connected device's name
                        break;
                    case Constants.MESSAGE_TOAST:
                        Toast.makeText(presenter.getContext(), msg.getData().getString(Constants.TOAST),
                                       Toast.LENGTH_SHORT).show();
                        break;
                }
            }
        }
    }
    
}
